﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Twodi.Resource
{
    /// <summary>
    /// Gerenciador de Recursos do Jogo.
    /// </summary>
    public class Resources
    {
        /// <summary>
        /// Jogo associado ao Resources.
        /// </summary>
        private static Game Game;

        /// <summary>
        /// Mapeamento de Recursos.
        /// </summary>
        private static Dictionary<Type, Dictionary<String, object>> MappedResources;

        /// <summary>
        /// Mapeamento do Content.
        /// </summary>
        private static Dictionary<Type, String> ContentPaths;

        /// <summary>
        /// Construtor padrão.
        /// </summary>
        /// <param name="game"></param>
        public Resources()
        {

        }

        /// <summary>
        /// Inicializar recursos.
        /// </summary>
        public static void Initialize(Game game)
        {
            Game = game;
            MappedResources = new Dictionary<Type, Dictionary<string, object>>();
            ContentPaths = new Dictionary<Type, string>();
        }

        public static bool Load<T>(params String[] names)
        {
            for (int i = 0; i < names.Length; i++)
            {
                if (!Load<T>(names[i])) return false;
            }

            return true;
        }

        /// <summary>
        /// Carregar recurso na memoria.
        /// </summary>
        /// <typeparam name="T">Tipo do recurso.</typeparam>
        /// <param name="name">Nome do recurso.</param>
        /// <returns></returns>
        public static bool Load<T>(String name)
        {
            CheckInitialized();

            Type type = typeof(T);

            //Tentar carregar recurso.
            T loadedResource = Game.Content.Load<T>(GetPath<T>(name));

            if (loadedResource != null)
            {
                //Recurso encontrado
                if (!MappedResources.ContainsKey(type))
                {
                    //Não há mapeamento para o tipo do recurso, então cria um.
                    MappedResources.Add(type, new Dictionary<String, object>());
                }

                //Recurso não existe
                if (!MappedResources[type].ContainsKey(name))
                {
                    //Adicionar recurso no mapeamento.
                    MappedResources[type].Add(name, loadedResource);
                }

                return true;
            }
            else
            {
                //Recurso não foi encontrando.
                Console.WriteLine("Recurso não encontrado.");
                return false;
            }
        }

        /// <summary>
        /// Recuperar recurso em memoria.
        /// </summary>
        /// <typeparam name="T">Tipo do recurso.</typeparam>
        /// <param name="name">Nome do recurso.</param>
        /// <returns></returns>
        public static T Get<T>(String name)
        {
            CheckInitialized();

            try
            {
                return (T)MappedResources[typeof(T)][name];
            }
            catch (Exception)
            {
                throw new Exception("Recurso não encontrado.");
            }
        }

        /// <summary>
        /// Carregar e recuperar recurso em memoria.
        /// </summary>
        /// <typeparam name="T">Tipo do recurso.</typeparam>
        /// <param name="name">Nome do recurso.</param>
        /// <returns></returns>
        public static T LoadGet<T>(String name)
        {
            CheckInitialized();

            if (Load<T>(name))
            {
                return Get<T>(name);
            }

            return default(T);
        }

        /// <summary>
        /// Adicionar mapeamento para o tipo.
        /// </summary>
        /// <typeparam name="T">Tipo do recurso para o mapeamento.</typeparam>
        /// <param name="path">Mapa dentro do content.</param>
        public static void AddPath<T>(String path)
        {
            CheckInitialized();

            Type type = typeof(T);
            if (!ContentPaths.Keys.Contains(type))
            {
                ContentPaths.Add(type, path + "//");
            }
            else
            {
                ContentPaths[type] = path;
            }
        }

        /// <summary>
        /// Pegar mapeamento para o tipo.
        /// </summary>
        /// <typeparam name="T">Tipo do recurso.</typeparam>
        /// <returns></returns>
        public static String GetPath<T>()
        {
            CheckInitialized();
            return ContentPaths[typeof(T)];
        }

        /// <summary>
        /// Pegar caminho para recurso do tipo T, adicionando nome do recurso.
        /// </summary>
        /// <typeparam name="T">Tipo do recurso.</typeparam>
        /// <param name="resource">Nome do recurso.</param>
        /// <returns></returns>
        public static String GetPath<T>(String resource)
        {
            CheckInitialized();
            if (ContentPaths.ContainsKey(typeof(T)))
            {
                return ContentPaths[typeof(T)] + resource;
            }
            else
            {
                return resource;
            }
        }

        /// <summary>
        /// Resources foram inicializados.
        /// </summary>
        protected static void CheckInitialized()
        {
            if (MappedResources == null || ContentPaths == null) throw new Exception("Resources não foi inicializado.");
        }

    }
}
